#include "gtkmain.h"
#include "gtksettings.h"
#include "gtkwidgetpath.h"
+#include "gtkpixelcacheprivate.h"
#include "a11y/gtktreeviewaccessibleprivate.h"
GdkWindow *bin_window;
GdkWindow *header_window;
+ GtkPixelCache *pixel_cache;
+
/* Scroll position state keeping */
GtkTreeRowReference *top_row;
gint top_row_dy;
guint in_grab : 1;
+ guint in_scroll : 1;
+
/* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
guint search_entry_avoid_unhandled_binding : 1;
static void update_prelight (GtkTreeView *tree_view,
int x,
int y);
+static void gtk_tree_view_queue_draw_region (GtkWidget *widget,
+ const cairo_region_t *region);
static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
widget_class->style_updated = gtk_tree_view_style_updated;
widget_class->grab_notify = gtk_tree_view_grab_notify;
widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
+ widget_class->queue_draw_region = gtk_tree_view_queue_draw_region;
/* GtkContainer signals */
container_class->remove = gtk_tree_view_remove;
tree_view->priv->headers_visible = TRUE;
tree_view->priv->activate_on_single_click = FALSE;
+ tree_view->priv->pixel_cache = _gtk_pixel_cache_new ();
+
/* We need some padding */
tree_view->priv->dy = 0;
tree_view->priv->cursor_offset = 0;
tree_view->priv->vadjustment = NULL;
}
+ if (tree_view->priv->pixel_cache)
+ _gtk_pixel_cache_free (tree_view->priv->pixel_cache);
+ tree_view->priv->pixel_cache = NULL;
+
GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
}
gtk_style_context_set_background (context, tree_view->priv->header_window);
}
+static void
+gtk_tree_view_bin_window_invalidate_handler (GdkWindow *window,
+ cairo_region_t *region)
+{
+ gpointer widget;
+ GtkTreeView *tree_view;
+ int y;
+
+ gdk_window_get_user_data (window, &widget);
+ tree_view = GTK_TREE_VIEW (widget);
+
+ /* Scrolling will invalidate everything in the bin window,
+ but we already have it in the cache, so we can ignore that */
+ if (tree_view->priv->in_scroll)
+ return;
+
+ y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
+ cairo_region_translate (region,
+ 0, y);
+ _gtk_pixel_cache_invalidate (tree_view->priv->pixel_cache, region);
+ cairo_region_translate (region,
+ 0, -y);
+}
+
+static void
+gtk_tree_view_queue_draw_region (GtkWidget *widget,
+ const cairo_region_t *region)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+
+ /* There is no way we can know if a region targets the
+ not-currently-visible but in pixel cache region, so we
+ always just invalidate the whole thing whenever the
+ tree view gets a queue draw. This doesn't normally happen
+ in normal scrolling cases anyway. */
+ _gtk_pixel_cache_invalidate (tree_view->priv->pixel_cache, NULL);
+
+ GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->queue_draw_region (widget,
+ region);
+}
+
static void
gtk_tree_view_realize (GtkWidget *widget)
{
tree_view->priv->bin_window = gdk_window_new (window,
&attributes, attributes_mask);
gtk_widget_register_window (widget, tree_view->priv->bin_window);
+ gdk_window_set_invalidate_handler (tree_view->priv->bin_window,
+ gtk_tree_view_bin_window_invalidate_handler);
gtk_widget_get_allocation (widget, &allocation);
bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
- cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
- cairo_clip (cr);
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
return TRUE;
return FALSE;
}
+static void
+draw_bin (cairo_t *cr,
+ gpointer user_data)
+{
+ GtkWidget *widget = GTK_WIDGET (user_data);
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ GList *tmp_list;
+
+ cairo_save (cr);
+
+ gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
+ gtk_tree_view_bin_draw (widget, cr);
+
+ cairo_restore (cr);
+
+ /* We can't just chain up to Container::draw as it will try to send the
+ * event to the headers, so we handle propagating it to our children
+ * (eg. widgets being edited) ourselves.
+ */
+ tmp_list = tree_view->priv->children;
+ while (tmp_list)
+ {
+ GtkTreeViewChild *child = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
+ }
+}
+
static gboolean
gtk_tree_view_draw (GtkWidget *widget,
cairo_t *cr)
if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
{
- GList *tmp_list;
-
- cairo_save (cr);
-
- gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
- gtk_tree_view_bin_draw (widget, cr);
+ cairo_rectangle_int_t view_rect;
+ cairo_rectangle_int_t canvas_rect;
- cairo_restore (cr);
+ view_rect.x = 0;
+ view_rect.y = gtk_tree_view_get_effective_header_height (tree_view);
+ view_rect.width = gdk_window_get_width (tree_view->priv->bin_window);
+ view_rect.height = gdk_window_get_height (tree_view->priv->bin_window);
- /* We can't just chain up to Container::draw as it will try to send the
- * event to the headers, so we handle propagating it to our children
- * (eg. widgets being edited) ourselves.
- */
- tmp_list = tree_view->priv->children;
- while (tmp_list)
- {
- GtkTreeViewChild *child = tmp_list->data;
- tmp_list = tmp_list->next;
+ gdk_window_get_position (tree_view->priv->bin_window, &canvas_rect.x, &canvas_rect.y);
+ canvas_rect.y = -gtk_adjustment_get_value (tree_view->priv->vadjustment);
+ canvas_rect.width = gdk_window_get_width (tree_view->priv->bin_window);
+ canvas_rect.height = tree_view->priv->height;
- gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
- }
+ _gtk_pixel_cache_draw (tree_view->priv->pixel_cache, cr, tree_view->priv->bin_window,
+ &view_rect, &canvas_rect,
+ draw_bin, widget);
}
gtk_style_context_save (context);
GtkRBTree *tree,
GtkRBNode *node)
{
- GtkAllocation allocation;
- gint y;
+ GdkRectangle rect;
- y = _gtk_rbtree_node_find_offset (tree, node)
- - gtk_adjustment_get_value (tree_view->priv->vadjustment)
- + gtk_tree_view_get_effective_header_height (tree_view);
+ rect.x = 0;
+ rect.y =
+ _gtk_rbtree_node_find_offset (tree, node)
+ - gtk_adjustment_get_value (tree_view->priv->vadjustment);
+ rect.width = gtk_widget_get_allocated_width (GTK_WIDGET (tree_view));
+ rect.height = GTK_RBNODE_GET_HEIGHT (node);
- gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
- gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
- 0, y,
- allocation.width,
- GTK_RBNODE_GET_HEIGHT (node));
+ gdk_window_invalidate_rect (tree_view->priv->bin_window,
+ &rect, TRUE);
}
static gboolean
}
}
}
+ tree_view->priv->in_scroll = TRUE;
gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
+ tree_view->priv->in_scroll = FALSE;
if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
{